package study.springboot.mvc.support.servlet;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.tomcat.util.http.MimeHeaders;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;

@Slf4j
public class RRHttpRequestWrapper extends HttpServletRequestWrapper {

    /* 原生body */
    private byte[] rawBody;

    public RRHttpRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            rawBody = IOUtils.toByteArray(request.getInputStream());
            if (rawBody == null || rawBody.length == 0) {
                rawBody = "{}".getBytes();
                reflectSetparam(request, "content-type", "application/json");
            }
        } catch (Exception ex) {
            throw new RuntimeException("", ex);
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (rawBody != null) {
            return new RReadServletInputStream(rawBody);
        }
        return super.getInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream(), getCharacterEncoding()));
    }

    @Override
    public String getParameter(String name) {
        return super.getParameter(name);
    }

    public static void reflectSetparam(HttpServletRequest request, String key, String value) {
        //
        Class<?> clazz = request.getClass();
        log.info("{}", clazz.getName());
        try {
            //request
            Field f1 = clazz.getDeclaredField("request");
            f1.setAccessible(true);
            Object reqObj = f1.get(request);
            //coyoteRequest
            Field f2 = reqObj.getClass().getDeclaredField("coyoteRequest");
            f2.setAccessible(true);
            Object coyoteObj = f2.get(reqObj);
            //System.out.println("coyoteRequest实现类="+o1.getClass().getName());
            //headers
            Field f3 = coyoteObj.getClass().getDeclaredField("headers");
            f3.setAccessible(true);
            MimeHeaders headers = (MimeHeaders) f3.get(coyoteObj);
            headers.addValue(key)
                    .setString(value);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * ServletInputStream
     */
    public class RReadServletInputStream extends ServletInputStream {

        /*  */
        private ByteArrayInputStream bis;

        public RReadServletInputStream(byte[] bytes) {
            bis = new ByteArrayInputStream(bytes);
        }

        @Override
        public int read() throws IOException {
            return bis.read();
        }

        @Override
        public boolean isFinished() {
            return bis.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
        }
    }
}
